﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using ProjectBase.Core.Web;
using StructureMap.Configuration.DSL;

using ProjectBase.Core;
using ProjectBase.Core.Storage;

using StructureMap.Configuration.DSL.Expressions;

namespace $safeprojectname$.IoC
{
    [CLSCompliant(false)]
    public class DefaultProfileRegistry : Registry
    {
        public static string ProfileName { get { return "Default"; } }

        public DefaultProfileRegistry()
        {
            SetScans(this, ProfileName);
            SetSetterInjection(this);
            Profile(ProfileName, SetDefaults);
        }

        public static void SetDefaults(ProfileExpression x)
        {
            x.For<ISessionStorageProvider>()
             .Use(new ProxyInstance(typeof(DefaultSessionStorageProvider)))
                //.Use(new ProxyInstance(typeof(ProfileSessionStorageProvider))) // needs Profile enabled
                ;

            // TODO e.g. Employee
            //x.For<EntityResolver<Employee, int>>()
            // .Use(new ProxyInstance(typeof(EmployeeResolver)));
        }

        private static readonly IList<Type> TypesToExclude = new List<Type>
        {
            // skip DB for translations
            typeof (Data.Services.TranslatorDao),
            typeof (Data.Services.LangDao),

            // skip DB for Documentation
            typeof (Data.Services.ArticleDao),
            typeof (Data.Services.ArticleGroupDao),
            typeof (Data.Services.ArticleCategoryDao),
            typeof (Data.Services.ContentTypeDao),

            // skip DB or XML for Service objects
            typeof (Data.Services$DefaultIsXml$.UserDao),
        };

        private static bool DefaultAssemblyPredicate(Assembly assembly)
        {
            // TODO exclude not default
            return !assembly.FullName.Contains(".Profile2,");
        }

        private static bool DefaultTypePredicate(Type type)
        {
            if (TypesToExclude.Contains(type))
            {
                return true;
            }
            return false;
        }

        public static void SetScans(IRegistry x, string profileName, Func<Assembly, bool> assemblyPredicate = null, Func<Type, bool> typePredicate = null)
        {
            assemblyPredicate = assemblyPredicate ?? DefaultAssemblyPredicate;
            typePredicate = typePredicate ?? DefaultTypePredicate;

            // wrapped with proxy
            x.Scan(s =>
            {
                s.AssembliesFromApplicationBaseDirectory(
                    af => af.FullName.StartsWith("ProjectBase")
                       ||
                       (
                          af.FullName.StartsWith("$prjsn$")
                          && assemblyPredicate(af)
                       ));

                s.Exclude(type => !type.IsClass);
                s.Exclude(type => type.IsAbstract);
                s.Exclude(typePredicate);

                s.Include(type => type.GetInterfaces().Any(t => t.IsEquivalentTo(typeof(IService))));

                ProxyConvention.ProfileName = profileName;
                s.Convention<ProxyConvention>();

                s.WithDefaultConventions();
            });
        }

        public static void SetSetterInjection(IRegistry x)
        {
            x.SetAllProperties
            (
                set => set.TypeMatches
                (
                    type => type != typeof(IEntityModel<,>) // not intended for IoC
                         && type != typeof(IViewModel)       // not intended for IoC
                         && type.GetInterfaces().Any(i => i.IsEquivalentTo(typeof(IService)))
                )
            );

            // Messages act as only ONE instance for any IMessageHolder in the scope of a single Request
            x.SetAllProperties(set => set.OfType<Messages>());
            x.For<Messages>()
                .HybridHttpOrThreadLocalScoped()
                .Use<Messages>();
        }
    }
}